﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using LingDong.ConfigProvider;
using NLog;

namespace LingDong.DataProvider
{
    /// <summary>
    /// PeopleDaily corpus is a labeled corpus
    /// Several lines of input file makes up a data, 
    /// each data are separated from a empty line
    /// the format is:
    /// <doc>
    /// <url>title or url</url><content>content</content>
    /// <url>title or url</url><content>content</content>
    /// </doc>
    /// e.g: 20000101-01-001-001/m  二○○○年/t  贺词/n  
    /// </summary>
    public class PeopleDailyReader : IDataReader
    {
        #region Contructors

        public PeopleDailyReader()
        {
            logger = LogManager.GetCurrentClassLogger();

            InitDataFileList();
            ChangeToNextFile();
        }

        #endregion
        

        #region Public Members

        /// <summary>
        /// Get next text data from people daily corpus
        /// </summary>
        /// <returns></returns>
        public DataEntity GetNextData()
        {
            if (reader.EndOfStream)
            {
                if (!ChangeToNextFile())
                    return null;
            }

            string url = String.Empty;
            StringBuilder content = new StringBuilder();
            string line = reader.ReadLine();
            while (!String.IsNullOrEmpty(line))
            {
                string[] terms = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                int len = terms.Length;
                // skip the first
                for (int i = 1; i < len; i++)
                {
                    // remove labeled POS
                    int index = terms[i].LastIndexOf('/');
                    if (index < 0)
                        continue;
                    string term = terms[i].Substring(0, index);
                    content.Append(term);
                }

                if (String.IsNullOrEmpty(url))
                    url = terms[0].Substring(0, 15);

                line = reader.ReadLine();
            }

            DataEntity data = new DataEntity();
            data.Url = url;
            data.Content = content.ToString();
            return data;
        }

        /// <summary>
        /// Return if all data in data file has been read
        /// </summary>
        /// <returns></returns>
        public bool IsAllDataRead()
        {
            return reader.EndOfStream && currentDataFileIndex <= 0;
        }

        /// <summary>
        /// PeopleDaily corpus contains only text
        /// </summary>
        /// <returns></returns>
        public bool IsDataContainsOnlyText()
        {
            return true;
        }

        #endregion


        #region Private Methods

        private void InitDataFileList()
        {
            string encode = ConfigDataProvider.Default.PeopleDailyDataEncode;
            defaultEncoding = Encoding.GetEncoding(encode);

            string path = ConfigDataProvider.Default.PeopleDailyDataPath;
            // given path is a single file
            if (File.Exists(path))
            {
                fileNameList = new List<string>();
                fileNameList.Add(path);
            }
            // given path is a directory, add all files in it
            else if (Directory.Exists(path))
            {
                fileNameList = Directory.GetFiles(path, "*", SearchOption.AllDirectories).ToList();
            }
            else
            {
                throw new ArgumentException("path");
            }

            currentDataFileIndex = fileNameList.Count;
        }

        private bool ChangeToNextFile()
        {
            if (--currentDataFileIndex < 0)
                return false;

            string curFileName = fileNameList[currentDataFileIndex];
            logger.Debug("PeopleDaily data reader, reading file: {0}", curFileName);
            try
            {
                reader = new StreamReader(curFileName, defaultEncoding);
            }
            catch (Exception ex)
            {
                logger.Error("Cannot open PeopleDaily data file: {0}", ex.Message);
                throw;
            }
            return true;
        }

        #endregion


        #region Private Members

        private StreamReader reader;

        private Logger logger;

        private Encoding defaultEncoding;
        private int currentDataFileIndex;
        private List<string> fileNameList;

        #endregion
        

        #region Disposable related

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // protect from being called multiple times.
            if (disposed)
            {
                return;
            }

            if (disposing)
            {
                // clean up all managed resources.
                if (reader != null)
                {
                    reader.Dispose();
                }
            }

            disposed = true;
        }

        private bool disposed = false;

        #endregion
    }
}
